
import backtrader as bt

class CBollingerBandsStrategy(bt.Strategy):
    params = (
        ("period", 15), ## 时间窗口，确定中轨的均线周期，默认为20日均线
        ("devfactor", 1) ## 标准差系数，作用是控制上下轨和中轨的距离，默认为2
    )

    def __init__(self):
        self.bbands = bt.indicators.BollingerBands(period=self.params.period, devfactor=self.params.devfactor)
        self.order = None

    def next(self):
        if self.order:
            return
 
        if self.data.close[0] > self.bbands.lines.top[0]:
            if self.position.size == 0:
                commission_info = self.broker.getcommissioninfo(self.data)
                cash = self.broker.get_cash() - commission_info.getsize(1, self.data.close[0])
                size = cash // self.data.close[0]
                self.buy(size=size)
                print(f'BUY: {size} shares')
        
        elif self.data.close[0] < self.bbands.lines.bot[0]:
            if self.position.size > 0:
                size = self.position.size
                self.close(size=size)
                print(f'SELL: {size} shares')
    
    def notify_order(self, order):
        if order.status in [order.Submitted, order.Accepted]:
            return
 
        if order.status in [order.Completed]:
            if order.isbuy():
                print(f'BUY executed at {self.data.num2date(order.executed.dt).date()}, Price: {order.executed.price:.2f}, Cost: {order.executed.value:.2f}, Comm: {order.executed.comm:.2f}')
            elif order.issell():
                cost = order.executed.value
                profit = order.executed.value - order.created.size * order.created.price
                profit_percent = (profit / cost) * 100
                print(f'SELL executed at {self.data.num2date(order.executed.dt).date()}, Price: {order.executed.price:.2f}, Cost: {cost:.2f}, Profit: {profit:.2f}, Profit %: {profit_percent:.2f}%')
 
        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            print('Order Canceled/Margin/Rejected')